#include "../includes/DiskManager.h"
#include <iostream>
#include <string>
#include <sys/types.h>


DiskManager* DiskManager::instance_ = nullptr;

DiskManager& DiskManager::getInstance(const std::string& path){ // 由于有默认值, 所以第二次调用getinstance()方法时可不用输入文件路径

    if(instance_ == nullptr){
        instance_ = new DiskManager(path);
    }
    return *instance_;
}

DiskManager::DiskManager(const std::string& path){
    file_path_ = path;
    DiskDriver::getInstance(path); // 初始化一个DiskDriver
}

// 将超级块信息写入磁盘
int DiskManager::super_block_set(SuperBlock &super_block){
    DiskDriver& disk_driver = DiskDriver::getInstance();
    return disk_driver.d_write(&super_block, sizeof(super_block), 0); 
}

int DiskManager::super_block_load(SuperBlock &super_block){
    DiskDriver& disk_driver = DiskDriver::getInstance();
    // 直接传递引用的地址
    return disk_driver.d_read(&super_block, sizeof(super_block), 0);
}

int DiskManager::super_block_clear(){ // 格式化磁盘
    SuperBlock super_block;
    super_block.inode_start = 420; // inode表从第420个字节的位置开始
    super_block.data_start = 111780; // 数据区起始地址
    std::memset(super_block.inode_state, 0, sizeof super_block.inode_state);
    std::memset(super_block.data_state, 0, sizeof super_block.data_state);
    return super_block_set(super_block); // 将格式化信息写入磁盘
}

int DiskManager::new_inode(const std::string &path){
    if(path.size() > PATH_LEN)return -1; // 文件名不合法

    // 创建一个新的inode, 创建失败返回-1, 创建成功返回该inode的id
    SuperBlock super_block;
    super_block_load(super_block); // 先读取超级块的状态
    int loc = -1;
    for(int i = 0; i < INODE_NUM; i++){
        if(!super_block.inode_state[i]){
            loc = i;
            break;
        }
    }
    if(loc != -1){
        Inode inode;
        inode.id =  loc;
        strcpy(inode.path, path.c_str()); // 字符串拷贝
        super_block.inode_state[loc] = 1;
        super_block_set(super_block);
        inode_set(loc, inode); // 写回到磁盘
    }
    return loc;
}

int DiskManager::inode_del(int id){
    // 根据id查询, 删除一个inode, 删除失败返回-1
    SuperBlock super_block;
    super_block_load(super_block); // 先读取超级块的状态
    super_block.inode_state[id] = 0;
    
    Inode inode;
    inode_get(id, inode);
    for(int i = 0; i < inode.block_num; i++){
        super_block.data_state[inode.blocks[i]] = 0; // 将数据区的占位置空
    }

    return super_block_set(super_block); // 修改后写回磁盘
}

int DiskManager::inode_del(const std::string &path){
    // 根据文件路径查询, 删除一个inode, 删除失败返回-1

    // 先根据路径查找id
    Inode inode;
    int inode_id = inode_get(path, inode);
    if(inode_id == -1)return -1;

    // 再根据id删除
    return inode_del(inode_id);
}

int DiskManager::inode_get(const std::string &path, Inode &inode){
    // 根据文件路径查询其所对应的inode, 查询失败返回-1, 查询成功将把信息填写到inode引用中 
    DiskDriver& disk_driver = DiskDriver::getInstance();

    SuperBlock super_block;
    super_block_load(super_block); // 先读取超级块的状态

    for(int i = 0; i < INODE_NUM; i++){
        if(super_block.inode_state[i]){
            off_t offset = inode_id_to_offset(i);
            disk_driver.d_read(&inode, sizeof(inode), offset); // 从磁盘读取inode节点信息
            if(strcmp(inode.path, path.c_str()) == 0){ // 比较两个路径是否一致
                return i;
            }
        }
    }   
    return -1; 
}

int DiskManager::inode_get(int id, Inode &inode){
    // 根据id查询其所对应的inode, 查询失败返回-1, 查询成功将把信息填写到inode引用中 
    DiskDriver& disk_driver = DiskDriver::getInstance();

    SuperBlock super_block;
    super_block_load(super_block); // 先读取超级块的状态
    if(!super_block.inode_state[id]) return -1; // 该inode无效

    off_t offset = inode_id_to_offset(id);
    return disk_driver.d_read(&inode, sizeof(inode), offset);
}

int DiskManager::inode_set(int id, Inode &inode){
    // 修改inode的值
    off_t offset = inode_id_to_offset(id);
    DiskDriver& disk_driver = DiskDriver::getInstance();
    return disk_driver.d_write(&inode, sizeof(inode), offset);
}

off_t DiskManager::inode_id_to_offset(int id) {
    // 简单边界检查
    if (id < 0 || id >= INODE_NUM) {
        return -1;  // 或抛出异常
    }
    
    // 直接计算（off_t 通常足够大）
    return static_cast<off_t>(SUPER_BLOCK_SIZE) + 
           static_cast<off_t>(id) * static_cast<off_t>(INODE_SIZE);
}

int DiskManager::new_data_block(){
    // 从数据区分配一个数据块, 块大小为1024B, 返回该块在数据区的位置索引, 分配失败返回-1
    SuperBlock super_block;
    super_block_load(super_block); // 先读取超级块的状态
    for(int i = 0; i < DATA_NUM; i++){
        if(!super_block.data_state[i]){
            super_block.data_state[i] = true;
            if(super_block_set(super_block) == -1)return -1; // 修改超级块的状态, 写回磁盘
            return i;
        }
    } 
    return -1; // 当前已经不存在空闲块
}

int DiskManager::data_block_write(int id, void* buff, size_t size, off_t inner_off){
    // 在第id个数据块中写入大小为size的数据
    off_t offset = data_block_id_to_offset(id);
    offset += inner_off; // 数据块的起始地址加上块内偏移量构成写数据的最终偏移量
    DiskDriver& disk_driver = DiskDriver::getInstance();
    return disk_driver.d_write(buff, size, offset);
}

int DiskManager::data_block_read(int id, void* buff, size_t size, off_t inner_off){
    // 从第id个数据块中读取大小为size的数据
    off_t offset = data_block_id_to_offset(id);
    offset += inner_off; // 数据块的起始地址加上块内偏移量构成读数据的最终偏移量
    DiskDriver& disk_driver = DiskDriver::getInstance();
    return disk_driver.d_read(buff, size, offset);
}

int DiskManager::data_block_del(int id){
    // 删除第id个数据块
    SuperBlock super_block;
    super_block_load(super_block); // 先读取超级块的状态
    super_block.data_state[id] = false;
    return super_block_set(super_block); // 修改超级块的状态后写回磁盘
}

off_t DiskManager::data_block_id_to_offset(int id){
    // 将数据块索引转为实际的磁盘地址偏移量

    // 简单边界检查
    if(id < 0 || id >= DATA_NUM){
        return -1;
    }
    return static_cast<off_t>(SUPER_BLOCK_SIZE) + 
           static_cast<off_t>(INODE_NUM) * static_cast<off_t>(INODE_SIZE) + 
           static_cast<off_t>(id) * static_cast<off_t>(BLOCK_SIZE);
}